package com.clt.ess.base;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * 这是一个生成授权码的类
 */
public class KeyGen {
    private static final String LL = "chenxk";// 这居然似乎就算是判断结果是否有效的私钥诶。。

    public String getSerial(String userId, String unicodeMark,
                            String licenseNum, int year)
    {
        java.util.Calendar cal = java.util.Calendar.getInstance();
        cal.add(Calendar.YEAR, year);
        cal.add(Calendar.DAY_OF_YEAR, -1);
        java.text.NumberFormat nf = new java.text.DecimalFormat("000");
        licenseNum = nf.format(Integer.valueOf(licenseNum));
        String verTime = new StringBuilder("-")
                .append(new java.text.SimpleDateFormat("yyyyMMdd").format(cal
                        .getTime())).append("0").toString();
        String need = new StringBuilder(userId.replace("\\u", unicodeMark))
                .append("-").append(unicodeMark).append(licenseNum)
                .append(verTime).toString();
        String dx = new StringBuilder(need).append(KeyGen.LL).append(userId)
                .toString();
        int suf = this.decode(dx);
        String code = new StringBuilder(need).append(String.valueOf(suf))
                .toString();
        return change(code);
    }

    private int decode(String s)
    {
        int i;
        char[] ac;
        int j;
        int k;
        i = 0;
        ac = s.toCharArray();
        j = 0;
        k = ac.length;
        while (j < k)
        {
            i = (31 * i) + ac[j];
            j++;
        }
        return Math.abs(i);
    }

    /**
     * 其中用到的编码转换规则，请参见KeyGen.txt
     *
     * @param s
     * @return
     */
    public String change(String s)
    {
        char[] abyte0;
        char[] ac;
        int i;
        int k;
        int j;
        abyte0 = s.toCharArray();
        ac = new char[abyte0.length];
        i = 0;
        k = abyte0.length;
        while (i < k)
        {
            j = abyte0[i];
            if ((j >= 48) && (j <= 57))
            {
                j = (((j - 48) + 5) % 10) + 48;
            }
            else if ((j >= 65) && (j <= 90))
            {
                j = (((j - 65) + 13) % 26) + 65;
            }
            else if ((j >= 97) && (j <= 122))
            {
                j = (((j - 97) + 13) % 26) + 97;
            }
            else if ((j >= 19968) && (j <= 40959))// 4E00..9FFF;
            {
                j = (((j - 19968) + 10496) % 20992) + 19968;
            }
            ac[i] = (char) j;
            i++;
        }
        return String.valueOf(ac);
    }

    public List<String> getInfo(String strSerial)
    {
        List<String> result=new ArrayList<String>();
        strSerial = change(strSerial);
        String[] infoStrings = strSerial.split("-");
        if (infoStrings.length >= 3)
        {
            String unicodeMark = infoStrings[1].substring(0,
                    infoStrings[1].length() - 3);
            infoStrings[0] = infoStrings[0].replace(unicodeMark, "\\u");
            infoStrings[0] = fromEncodedUnicode(infoStrings[0]);
            infoStrings[1] = infoStrings[1].substring(unicodeMark.length(), unicodeMark.length()+3);
            infoStrings[2] = infoStrings[2].substring(0, 8);
            result.add(infoStrings[0]);
            result.add(infoStrings[1]);
            result.add(infoStrings[2]);
            return result;
        }
        else
        {
            return null;
        }
    }

    public static void main(String[] args)
    {
        String userId = null;
        userId = "印章";
        KeyGen keyGen = new KeyGen();
        String res = keyGen.getSerial(
                toEncodedUnicode(userId, false), "654321", "999",
                3);
        System.out.println("Serial:" + res);
        System.out.println("Info:" + keyGen.getInfo(res).toString());
    }







    private static final char[] hexDigit = { '0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    private static char toHex(int nibble)
    {

        return hexDigit[(nibble & 0xF)];

    }

    /**
     *
     * 将字符串编码成 Unicode 形式的字符串. 如 "黄" to "\u9EC4" * Converts unicodes to encoded
     * \\uxxxx and escapes * special characters with a preceding slash
     *
     * @param theString
     *            待转换成Unicode编码的字符串。
     * @param escapeSpace
     *            是否忽略空格，为true时在空格后面是否加个反斜杠。 *
     * @return 返回转换后Unicode编码的字符串。
     */
    public static String toEncodedUnicode(String theString, boolean escapeSpace)
    {

        int len = theString.length();
        int bufLen = len * 2;
        if (bufLen < 0)
        {
            bufLen = Integer.MAX_VALUE;
        }
        StringBuffer outBuffer = new StringBuffer(bufLen);
        for (int x = 0; x < len; x++)
        {
            char aChar = theString.charAt(x);
            // Handle common case first, selecting largest block that
            // avoids the specials below
            if ((aChar > 61) && (aChar < 127))
            {
                if (aChar == '\\')
                {
                    outBuffer.append('\\');
                    outBuffer.append('\\');
                    continue;
                }
                outBuffer.append(aChar);
                continue;
            }
            switch (aChar)
            {
                case ' ':
                    if (x == 0 || escapeSpace) outBuffer.append('\\');
                    outBuffer.append(' ');
                    break;
                case '\t':
                    outBuffer.append('\\');
                    outBuffer.append('t');
                    break;
                case '\n':
                    outBuffer.append('\\');
                    outBuffer.append('n');
                    break;
                case '\r':
                    outBuffer.append('\\');
                    outBuffer.append('r');
                    break;
                case '\f':
                    outBuffer.append('\\');
                    outBuffer.append('f');
                    break;
                case '=': // Fall through
                case ':': // Fall through
                case '#': // Fall through
                case '!':
                    outBuffer.append('\\');
                    outBuffer.append(aChar);
                    break;
                default:
                    if ((aChar < 0x0020) || (aChar > 0x007e))
                    {
                        // 每个unicode有16位，每四位对应的16进制从高位保存到低位
                        outBuffer.append('\\');
                        outBuffer.append('u');
                        outBuffer.append(toHex((aChar >> 12) & 0xF));
                        outBuffer.append(toHex((aChar >> 8) & 0xF));
                        outBuffer.append(toHex((aChar >> 4) & 0xF));
                        outBuffer.append(toHex(aChar & 0xF));
                    }
                    else
                    {
                        outBuffer.append(aChar);
                    }
            }
        }
        return outBuffer.toString();
    }

    /**
     * 从 Unicode 形式的字符串转换成对应的编码的特殊字符串。 如 "\u9EC4" to "黄". Converts encoded
     * \\uxxxx to unicode chars and changes special saved chars to their
     * original forms
     *
     * @param in
     *            Unicode编码的字符数组。
     * @param off
     *            转换的起始偏移量。
     * @param len
     *            转换的字符长度。
     * @return 完成转换，返回编码前的特殊字符串。
     */
    public static String fromEncodedUnicode(char[] in, int off, int len)
    {
        char aChar;
        char[] out = new char[len]; // 只短不长
        int outLen = 0;
        int end = off + len;
        while (off < end)
        {
            aChar = in[off++];
            if (aChar == '\\')
            {
                aChar = in[off++];
                if (aChar == 'u')
                {
                    // Read the xxxx
                    int value = 0;
                    for (int i = 0; i < 4; i++)
                    {
                        aChar = in[off++];
                        switch (aChar)
                        {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed \\uxxxx encoding.");
                        }
                    }
                    out[outLen++] = (char) value;
                }
                else
                {
                    if (aChar == 't')
                    {
                        aChar = '\t';
                    }
                    else if (aChar == 'r')
                    {
                        aChar = '\r';
                    }
                    else if (aChar == 'n')
                    {
                        aChar = '\n';
                    }
                    else if (aChar == 'f')
                    {
                        aChar = '\f';
                    }
                    out[outLen++] = aChar;
                }
            }
            else
            {
                out[outLen++] = (char) aChar;
            }
        }
        return new String(out, 0, outLen);
    }

    public static String fromEncodedUnicode(String str, int off, int length)
    {
        return fromEncodedUnicode(str.toCharArray(),off,length);
    }

    public static String fromEncodedUnicode(String str)
    {
        return fromEncodedUnicode(str.toCharArray(),0,str.length());
    }


}
